package com.nit.netty.worker;

import com.nit.netty.codec.JSONDecoder;
import com.nit.netty.codec.JSONEncoder;
import com.nit.netty.handler.NettyServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

import javax.annotation.PreDestroy;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @Author: whb
 * @Description:
 * @CreateTime: 2020/8/21 13:49
 */
public class ServerWorker extends ChannelInitializer {

    private static final Logger logger = Logger.getLogger(ServerWorker.class.getName());
    private String remoteAddress;
    private Map<String, Object> serviceMap;
    EventLoopGroup bossGroup;
    EventLoopGroup workerGroup;
    NettyServerHandler handler;

    // 这里是服务端绑定地址与服务的地方
    public ServerWorker(String remoteAddress, Map<String, Object> serviceMap) {
        this.remoteAddress = remoteAddress;
        this.serviceMap = serviceMap;
        this.handler = new NettyServerHandler(this.serviceMap);
    }

    public void open() throws Exception {
        ServerBootstrap bootstrap = new ServerBootstrap();
        // 无参构造器使用默认个数
        //DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
        //                "io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
        // cpu核心数*2
        this.bossGroup = new NioEventLoopGroup();
        // 一个channel的生命周期位于一个eventLoop中, 一个LoopGroup下有许多loop, 一个loop与一个Thread绑定
        // 但是一个eventLoop可能会有多个channel
        this.workerGroup = new NioEventLoopGroup();
        try {
            // bossGroup用于分配新建立的连接给workerGroup中的eventLoop
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childHandler(this);
            String[] hostAndPort = this.remoteAddress.split(":");
            if (hostAndPort == null || hostAndPort.length != 2) {
                throw new RuntimeException("remoteAddress是一个错误的地址.");
            }
            ChannelFuture cf = bootstrap.bind(hostAndPort[0], Integer.parseInt(hostAndPort[1])).sync();
            logger.info("netty 服务器启动.监听端口:" + hostAndPort[1]);
            // 监听closeFuture事件, 并且sync阻塞当前线程
            cf.channel().closeFuture().sync();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "netty服务端启动失败", e);
        } finally {

        }

    }

    @Override
    protected void initChannel(Channel channel) throws Exception {
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast(new IdleStateHandler(0, 0, 60));
        pipeline.addLast(new JSONEncoder());
        pipeline.addLast(new JSONDecoder());
        pipeline.addLast(this.handler);
    }

    @PreDestroy
    private void destroy() {
        this.bossGroup.shutdownGracefully();
        this.workerGroup.shutdownGracefully();
    }
}

